home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / program / cpp112.zoo / src / if_expr.c < prev    next >
C/C++ Source or Header  |  1994-07-07  |  8KB  |  468 lines

  1.  
  2. /*---------------------------------------------------------------------*\
  3. |                                    |
  4. | CPP -- a stand-alone C preprocessor                    |
  5. | Copyright (c) 1993 Hacker Ltd.        Author: Scott Bigham    |
  6. |                                    |
  7. | Permission is granted to anyone to use this software for any purpose    |
  8. | on any computer system, and to redistribute it freely, with the    |
  9. | following restrictions:                        |
  10. | - No charge may be made other than reasonable charges for repro-    |
  11. |     duction.                                |
  12. | - Modified versions must be clearly marked as such.            |
  13. | - The author is not responsible for any harmful consequences of    |
  14. |     using this software, even if they result from defects therein.    |
  15. |                                    |
  16. | if_expr.c -- evaluate expression in an #if directive            |
  17. \*---------------------------------------------------------------------*/
  18.  
  19. #include <stdlib.h>
  20. #include <setjmp.h>
  21. #include <ctype.h>
  22. #include "global.h"
  23. #include "ztype.h"
  24.  
  25. typedef struct {
  26.   long l;
  27.   char uns;
  28. } Long;
  29.  
  30. static jmp_buf punt;
  31.  
  32. static char char_const(s)
  33.   register char *s;
  34. {
  35.   char val = 0;
  36.  
  37.   for (; *s != '\''; s++)
  38.     switch (*s) {
  39.     case '\\':
  40.       switch (*++s) {
  41.       case 'n':
  42.     val = '\n';
  43.     break;
  44.       case 't':
  45.     val = '\t';
  46.     break;
  47.       case 'v':
  48.     val = '\v';
  49.     break;
  50.       case 'b':
  51.     val = '\b';
  52.     break;
  53.       case 'r':
  54.     val = '\r';
  55.     break;
  56.       case 'f':
  57.     val = '\f';
  58.     break;
  59.       case 'a':
  60.     val = '\a';
  61.     break;
  62.       case '0':
  63.       case '1':
  64.       case '2':
  65.       case '3':
  66.       case '4':
  67.       case '5':
  68.       case '6':
  69.       case '7':
  70.     val = (*s++) - '0';
  71.     if (is_octal(*s))
  72.       val = val << 3 + ((*s++) - '0');
  73.     if (is_octal(*s))
  74.       val = val << 3 + ((*s++) - '0');
  75.     break;
  76.       case 'x':
  77.     val = 0;
  78.     for (s++; isxdigit(*s); s++) {
  79.       val = (val << 4) + (
  80.                    isdigit(*s) ? (*s - '0') :
  81.                    islower(*s) ? (*s - 'a' + 10) :
  82.                    (*s - 'A' + 10)
  83.           );
  84.     }
  85.     s--;
  86.     break;
  87.       default:
  88.     val = *s;
  89.       }
  90.       break;
  91.     default:
  92.       val = *s;
  93.     }
  94.   return val;
  95. }
  96.  
  97. static char match(tok)
  98.   int tok;
  99. {
  100.   register TokenP T = exp_token();
  101.   char c = T->subtype;
  102.  
  103.   if (T->type == tok) {
  104.     free_token(T);
  105.     return c;
  106.   }
  107.   if (tok == UNARY_OP && T->type == ADD_OP) {
  108.     free_token(T);
  109.     return c;
  110.   }
  111.   push_tlist(T);
  112.   return '\0';
  113. }
  114.  
  115. static void fmatch(tok)
  116.   int tok;
  117. {
  118.   if (!match(tok))
  119.     longjmp(punt, 1);
  120. }
  121.  
  122. static Long l_or_expr __PROTO((void));
  123.  
  124. static Long primary_expr()
  125. {
  126.   Long L /* ={0L,'\0'} */ ;
  127.   register TokenP T;
  128.  
  129.   L.l = 0;
  130.   L.uns = '\0';
  131.   T = exp_token();
  132.   switch (T->type) {
  133.   case ID:
  134.     free_token(T);
  135.     return L;
  136.   case NUMBER:
  137.     L.l = T->val;
  138.     L.uns == !!(T->flags & UNS_VAL);
  139.     free_token(T);
  140.     return L;
  141.   case CHAR_CON:
  142.     L.l = char_const(token_txt(T) + 1);
  143.     free_token(T);
  144.     return L;
  145.   case LPAREN:
  146.     L = l_or_expr();
  147.     fmatch(RPAREN);
  148.     free_token(T);
  149.     return L;
  150.   default:
  151.     free_token(T);
  152.     longjmp(punt, 1);
  153.   }
  154. }
  155.  
  156. static Long unary_expr()
  157. {
  158.   Long L;
  159.   char op;
  160.  
  161.   if (!(op = match(UNARY_OP)))
  162.     return primary_expr();
  163.   switch (op) {
  164.   case '!':
  165.     L = unary_expr();
  166.     L.uns = 0;
  167.     L.l = !L.l;
  168.     return L;
  169.   case '~':
  170.     L = unary_expr();
  171.     L.l = ~L.l;
  172.     return L;
  173.   case '+':
  174.     return unary_expr();
  175.   case '-':
  176.     L = unary_expr();
  177.     L.l = -L.l;
  178.     return L;
  179.   default:
  180.     bugchk("'%c' is UNARY_OP in #if expr", op);
  181.     longjmp(punt, 2);
  182.   }
  183. }
  184.  
  185. static Long mul_expr()
  186. {
  187.   Long L1, L;
  188.   char op;
  189.  
  190.   L1 = unary_expr();
  191.   while (op = match(MUL_OP)) {
  192.     L = unary_expr();
  193.     if (L.uns)
  194.       L1.uns = 1;
  195.     switch (op) {
  196.     case '*':
  197.       L1.l *= L.l;
  198.       break;
  199.     case '%':
  200.       L1.l %= L.l;
  201.       break;
  202.     case '/':
  203.       if (L.l == 0) {
  204.     error("divide by zero in #if expr");
  205.     longjmp(punt, 2);
  206.       }
  207.       L1.l /= L.l;
  208.       break;
  209.     default:
  210.       bugchk("'%c' is MUL_OP in #if expr", op);
  211.       longjmp(punt, 2);
  212.     }
  213.   }
  214.   return L1;
  215. }
  216.  
  217. static Long add_expr()
  218. {
  219.   Long L1, L;
  220.   char op;
  221.  
  222.   L1 = mul_expr();
  223.   while (op = match(ADD_OP)) {
  224.     L = mul_expr();
  225.     if (L.uns)
  226.       L1.uns = 1;
  227.     switch (op) {
  228.     case '+':
  229.       L1.l += L.l;
  230.       break;
  231.     case '-':
  232.       L1.l -= L.l;
  233.       break;
  234.     default:
  235.       bugchk("'%c' is ADD_OP in #if expr", op);
  236.       longjmp(punt, 2);
  237.     }
  238.   }
  239.   return L1;
  240. }
  241.  
  242. static Long shift_expr()
  243. {
  244.   Long L1, L;
  245.   char op;
  246.  
  247.   L1 = add_expr();
  248.   while (op = match(SHIFT_OP)) {
  249.     L = add_expr();
  250.     if (L.uns)
  251.       L1.uns = 1;
  252.     switch (op) {
  253.     case '<':
  254.       L1.l <<= L.l;
  255.       break;
  256.     case '>':
  257.       L1.l >>= L.l;
  258.       break;
  259.     default:
  260.       bugchk("'%c' is SHIFT_OP in #if expr", op);
  261.       longjmp(punt, 2);
  262.     }
  263.   }
  264.   return L1;
  265. }
  266.  
  267. #define compare(L1,op,L2) \
  268.  ((L1.uns || L2.uns) ? (unsigned long)L1.l op (unsigned long)L2.l : \
  269.              L1.l op L2.l)
  270.  
  271. static Long rel_expr()
  272. {
  273.   Long L1, L;
  274.   char op;
  275.  
  276.   L1 = shift_expr();
  277.   while (op = match(REL_OP)) {
  278.     L = shift_expr();
  279.     switch (op) {
  280.     case '<':
  281.       L1.l = compare(L1, <, L);
  282.       L1.uns = 0;
  283.       break;
  284.     case '>':
  285.       L1.l = compare(L1, >, L);
  286.       L1.uns = 0;
  287.       break;
  288.     case '(':
  289.       L1.l = compare(L1, <=, L);
  290.       L1.uns = 0;
  291.       break;
  292.     case ')':
  293.       L1.l = compare(L1, >=, L);
  294.       L1.uns = 0;
  295.       break;
  296.     default:
  297.       bugchk("'%c' is REL_OP in #if expr", op);
  298.       longjmp(punt, 2);
  299.     }
  300.   }
  301.   return L1;
  302. }
  303.  
  304. static Long eq_expr()
  305. {
  306.   Long L1, L;
  307.   char op;
  308.  
  309.   L1 = rel_expr();
  310.   while ((op = match(EQ_OP))) {
  311.     L = rel_expr();
  312.     switch (op) {
  313.     case '=':
  314.       L1.l = compare(L1, ==, L);
  315.       L1.uns = 0;
  316.       break;
  317.     case '!':
  318.       L1.l = compare(L1, !=, L);
  319.       L1.uns = 0;
  320.       break;
  321.     default:
  322.       bugchk("'%c' is EQ_OP in #if expr", op);
  323.       longjmp(punt, 2);
  324.     }
  325.   }
  326.   return L1;
  327. }
  328.  
  329. static Long b_and_expr()
  330. {
  331.   Long L1, L;
  332.   char op;
  333.  
  334.   L1 = eq_expr();
  335.   while (op = match(B_AND_OP)) {
  336.     L = eq_expr();
  337.     if (L.uns)
  338.       L1.uns = 1;
  339.     switch (op) {
  340.     case '&':
  341.       L1.l &= L.l;
  342.       break;
  343.     default:
  344.       bugchk("'%c' is B_AND_OP in #if expr", op);
  345.       longjmp(punt, 2);
  346.     }
  347.   }
  348.   return L1;
  349. }
  350.  
  351. static Long b_xor_expr()
  352. {
  353.   Long L1, L;
  354.   char op;
  355.  
  356.   L1 = b_and_expr();
  357.   while (op = match(B_XOR_OP)) {
  358.     L = b_and_expr();
  359.     if (L.uns)
  360.       L1.uns = 1;
  361.     switch (op) {
  362.     case '^':
  363.       L1.l ^= L.l;
  364.       break;
  365.     default:
  366.       bugchk("'%c' is B_XOR_OP in #if expr", op);
  367.       longjmp(punt, 2);
  368.     }
  369.   }
  370.   return L1;
  371. }
  372.  
  373. static Long b_or_expr()
  374. {
  375.   Long L1, L;
  376.   char op;
  377.  
  378.   L1 = b_xor_expr();
  379.   while (op = match(B_OR_OP)) {
  380.     L = b_xor_expr();
  381.     if (L.uns)
  382.       L1.uns = 1;
  383.     switch (op) {
  384.     case '|':
  385.       L1.l |= L.l;
  386.       break;
  387.     default:
  388.       bugchk("'%c' is B_OR_OP in #if expr", op);
  389.       longjmp(punt, 2);
  390.     }
  391.   }
  392.   return L1;
  393. }
  394.  
  395. static Long l_and_expr()
  396. {
  397.   Long L1, L;
  398.   char op;
  399.  
  400.   L1 = b_or_expr();
  401.   while (op = match(L_AND_OP)) {
  402.     L = b_or_expr();
  403.     switch (op) {
  404.     case '&':
  405.       L1.l = L1.l && L.l;
  406.       L1.uns = 0;
  407.       break;
  408.     default:
  409.       bugchk("'%c' is L_AND_OP in #if expr", op);
  410.       longjmp(punt, 2);
  411.     }
  412.   }
  413.   return L1;
  414. }
  415.  
  416. static Long l_or_expr()
  417. {
  418.   Long L1, L;
  419.   char op;
  420.  
  421.   L1 = l_and_expr();
  422.   while (op = match(L_OR_OP)) {
  423.     L = l_and_expr();
  424.     switch (op) {
  425.     case '|':
  426.       L1.l = L1.l || L.l;
  427.       L1.uns = 0;
  428.       break;
  429.     default:
  430.       bugchk("'%c' is L_OR_OP in #if expr", op);
  431.       longjmp(punt, 2);
  432.     }
  433.   }
  434.   return L1;
  435. }
  436.  
  437. static Long expr()
  438. {
  439.   Long L;
  440.  
  441.   L = l_or_expr();
  442.   if (!match(EOL))
  443.     longjmp(punt, 1);
  444.   return L;
  445. }
  446.  
  447. int if_expr()
  448. {
  449.   Long L;
  450.   int r;
  451.  
  452.   change_mode(IF_EXPR, 0);
  453.   _tokenize_line();
  454.   switch (setjmp(punt)) {
  455.   case 0:
  456.     L = expr();
  457.     r = !!L.l;
  458.     break;
  459.   case 1:
  460.     error("syntax error in #if expr");
  461.     /* and fall through */
  462.   default:
  463.     r